#region
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using MidnightPeach.Components;
using MidnightPeach.Controls;
using MidnightPeach.EdmxTransformer;
using MidnightPeach.Engine.Generators.DataGenerators;
using MidnightPeach.Engine.Generators.ServiceGenerators;
using MidnightPeach.Engine.Packages;
using MidnightPeach.Engine.Schema.DataSchema;
using MidnightPeach.Engine.Schema.Extractors;
using MidnightPeach.Engine.Schema.ServiceSchema;
using MidnightPeach.Properties;
using MidnightPeach.SolutionCreating;
using Utility = MidnightPeach.Engine.Components.Utility;

#endregion

namespace MidnightPeach.Forms
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            LoadInitialDirectory();
        }

        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);

            if (DesignMode)
                return;

            BuildText();

            LoadHistoryItems();

            if (string.IsNullOrEmpty(Settings.Default.LastSavedFile))
                OpenFile("Memopad.mp");
            else if (File.Exists(Settings.Default.LastSavedFile))
                OpenFile(Settings.Default.LastSavedFile);

#if DEBUG
            mnuEdmxTransformer.PerformClick();
#endif
        }

        private void LoadInitialDirectory()
        {
            string directory = string.IsNullOrEmpty(Settings.Default.InitialDirectory)
                ? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
                : Settings.Default.InitialDirectory;

            ofdPackage.InitialDirectory = directory;
            sfdPackage.InitialDirectory = directory;
        }

        private void BuildText()
        {
            string text = string.Format("{0} - ver.{1}", Resources.MidnightPeach, GeneralUtility.GetVersionText());
            if (string.IsNullOrEmpty(uscPackage.CurrentPath) == false)
                text += " - " + Path.GetFileName(uscPackage.CurrentPath);

            Text = text;
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            RecentPackageList.Instance.Save();

            base.OnClosing(e);
        }

        #region menu item event handlers
        private void mnuNew_Click(object sender, EventArgs e)
        {
            uscPackage.New();

            BuildText();
        }

        private void mnuOpen_Click(object sender, EventArgs e)
        {
            if (ofdPackage.ShowDialog() != DialogResult.OK)
                return;

            Settings.Default.InitialDirectory = Path.GetDirectoryName(ofdPackage.FileName);

            OpenFile(ofdPackage.FileName);
        }

        private void OpenFile(string filePath)
        {
            uscPackage.Open(filePath);

            RecentPackageList.Instance.InsertAtZero(filePath);
            LoadHistoryItems();

            Settings.Default.LastSavedFile = filePath;

            BuildText();
        }

        private void mnuSave_Click(object sender, EventArgs e)
        {
            if (uscPackage.CurrentPath == null)
            {
                mnuSaveAs.PerformClick();
            }
            else
            {
                uscPackage.Save();

                MessageBox.Show(Resources.Saved);
            }
        }

        private void mnuSaveAs_Click(object sender, EventArgs e)
        {
            if (sfdPackage.ShowDialog() != DialogResult.OK)
                return;

            Settings.Default.InitialDirectory = Path.GetDirectoryName(sfdPackage.FileName);

            uscPackage.SaveAsNew(sfdPackage.FileName);

            MessageBox.Show(Resources.Saved);

            BuildText();
        }

        private void mnuExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void mnuGenerateData_Click(object sender, EventArgs e)
        {
            GenerateData();

            MessageBox.Show(Resources.Code_generation_has_done);
        }

        private void mnuGenerateService_Click(object sender, EventArgs e)
        {
            GenerateService();

            MessageBox.Show(Resources.Code_generation_has_done);
        }

        private void GenerateData()
        {
            var package = uscPackage.GetPackage();

            Generate(package, package.Templates.Where(x => x.SourceType == TemplateSourceType.Dbml), TemplateSourceType.Dbml);
        }

        private void GenerateService()
        {
            var package = uscPackage.GetPackage();

            Generate(package, package.Templates.Where(x => x.SourceType == TemplateSourceType.DataAssembly), TemplateSourceType.DataAssembly);
        }

        private void Generate(Package package, IEnumerable<Template> templates, TemplateSourceType templateSourceType)
        {
            Database database = DbmlSchemaExtractor.Instance.Extract(package.DbmlFilePath);
            Assembly assembly = templateSourceType == TemplateSourceType.DataAssembly
                ? AssemblySchemaExtractor.Instance.Extract(package.DataAssemblyPath)
                : null;

            foreach (var template in templates)
            {
                var code = GenerateSingle(package, template, database, assembly);

                try
                {
                    string directory = Path.GetDirectoryName(template.PathToWrite);
                    if (Directory.Exists(directory) == false)
                        Directory.CreateDirectory(directory);

                    File.WriteAllText(template.PathToWrite, code);
                }
                catch
                {
                    string message = string.Format(Resources.Can_t_save_to__0__, template.PathToWrite);
                    MessageBox.Show(message);
                }
            }
        }

        private string GenerateSingle(Package package, Template template, Database database, Assembly assembly)
        {
            string code = template.SourceType == TemplateSourceType.Dbml
                ? DataGenerator.Build(package, database, null, null, template.Body)
                : ServiceGenerator.Build(package, assembly, null, null, null, template.Body);

            template.GeneratedCode = code;

            return code;
        }

        private void mnuGenerateSln_Click(object sender, EventArgs e)
        {
            SolutionCreationForm form = new SolutionCreationForm();
            if (form.ShowDialog() == DialogResult.OK)
            {
                var error = SolutionCreator.Create(form.SolutionTemplate, form.SolutionName, form.Directory);

                if (error == null)
                {
                    if (MessageBox.Show(Resources.The_Solution_has_been_generated, Resources.Question, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                        Process.Start(SolutionCreator.SolutionFilePath);
                }
                else
                {
                    MessageBox.Show(Resources.Failed_to_generate_a_solution_ + Environment.NewLine + error);
                }
            }
        }

        private void mnuHelp_Click(object sender, EventArgs e)
        {
            Process.Start(@"http://kimgwajang.tistory.com/category/Midnight%20Peach");
        }

        private void mnuAbout_Click(object sender, EventArgs e)
        {
            AboutBox aboutBox = new AboutBox();
            aboutBox.ShowDialog();
        }
        #endregion

        private void uscPackage_GenerateButtonClicked(object sender, PackageControl.GenerateButtonClickedEventArgs e)
        {
            var package = uscPackage.GetPackage();

            Database database = DbmlSchemaExtractor.Instance.Extract(package.DbmlFilePath);
            Assembly assembly = AssemblySchemaExtractor.Instance.Extract(package.DataAssemblyPath);

            string generatedCode = GenerateSingle(package, e.Template, database, assembly);

            if (string.IsNullOrEmpty(e.Template.PathToWrite))
                return;

            File.WriteAllText(e.Template.PathToWrite, generatedCode);
            MessageBox.Show(Resources.Generated);
        }

        private void LoadHistoryItems()
        {
            mnuHistory.DropDownItems.Clear();

            int index = 1;
            foreach (var packageFilePath in RecentPackageList.Instance)
            {
                string text = string.Format("&{0} {1}", index++, packageFilePath);
                ToolStripMenuItem menuItem = new ToolStripMenuItem(text);
                menuItem.Size = new Size(152, 22);
                menuItem.Tag = packageFilePath;
                menuItem.Click += ToolStripMenuItem_Click;

                mnuHistory.DropDownItems.Add(menuItem);
            }
        }

        private void ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            uscPackage.Open((string) ((ToolStripMenuItem) sender).Tag);
        }

        private void mnuAddUpdateCheck_Click(object sender, EventArgs e)
        {
            if (ofdUpdateCheck.ShowDialog() != DialogResult.OK)
                return;

            var successed = Utility.AddUpdateCheckAttribute(ofdUpdateCheck.FileName);

            if (successed)
                MessageBox.Show(Resources.UpdateCheck_Never_has_added_to_all_columns);
            else
                MessageBox.Show(Resources.Oops);
        }

        private void mnuImportExternalFile_Click(object sender, EventArgs e)
        {
            if (ofdExternalFile.ShowDialog() == DialogResult.OK)
            {
                string targetPath = Path.Combine(Environment.CurrentDirectory, Path.GetFileName(ofdExternalFile.FileName));

                File.Copy(ofdExternalFile.FileName, targetPath, true);

                MessageBox.Show(string.Format("The file has been copied to {0}", targetPath));
            }
        }

        private void mnuEdmxTransformer_Click(object sender, EventArgs e)
        {
            if (File.Exists(uscPackage.EdmxPath) == false)
            {
                MessageBox.Show("Edmx file does NOT exist or is invalid.");
                return;
            }

            if (string.IsNullOrEmpty(uscPackage.CurrentPath))
            {
                MessageBox.Show("MP file does NOT exist.");
                return;
            }

            using (var form = new EdmxTransformerForm(uscPackage.EdmxPath, Path.GetDirectoryName(uscPackage.CurrentPath)))
            {
                form.ShowDialog();
            }
        }
    }
}